package com.atom.test.opengl

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.PixelFormat
import android.opengl.GLES30
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import androidx.appcompat.app.AppCompatActivity
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.atom.module.lib.opengles.draw.GlCircle
import com.atom.module.lib.opengles.egl.EGLHelper
import com.atom.module.lib.opengles.egl.EGLWrapper
import com.atom.module.lib.opengles.shader.GlScene
import com.atom.module.lib.opengles.shader.GlSimpleProgram
import com.atom.module.logger.Logger
import com.atom.test.opengl.gesture.*
import com.atom.test.opengl.utils.MatrixState
import java.util.*
import kotlin.math.roundToInt

class EGLActivity : AppCompatActivity(), GestureListener {

    private lateinit var surfaceView: SurfaceView
    private lateinit var wrapper: EGLWrapper
    private var flatProgram: GlSimpleProgram? = null

    private val scene = GlScene()
    private val circle = GlCircle()


    protected var panRecognizer = PanRecognizer()

    protected var pinchRecognizer = PinchRecognizer()

    protected var rotationRecognizer = RotationRecognizer()

    protected var allRecognizers = Arrays.asList(
        panRecognizer, pinchRecognizer, rotationRecognizer
    )

    private val drawAnimator = ValueAnimator.ofFloat(0F, 1F).also {
        it.repeatCount = ValueAnimator.INFINITE
        it.repeatMode = ValueAnimator.REVERSE
        it.duration = 1200
        it.interpolator = FastOutSlowInInterpolator()
        it.addUpdateListener { draw() }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        surfaceView = SurfaceView(this)
        surfaceView.setZOrderOnTop(true)
        surfaceView.holder.setFormat(PixelFormat.RGBA_8888)
        surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                Log.e("SHAPES", "CREATED." + Thread.currentThread().name)
                onSurfaceCreated(holder)
            }

            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int
            ) {

            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {
                onSurfaceDestroyed()
            }
        })
        surfaceView.setOnTouchListener { v, event ->
            var handled = false
            for (idx in 0 until allRecognizers.size) {
                handled = handled or allRecognizers[idx].onTouchEvent(event)
            }
            handled
        }
        for (entry in allRecognizers) {
            entry.addListener(this)
        }
        setContentView(surfaceView)
    }

    private fun onSurfaceCreated(holder: SurfaceHolder) {
        wrapper = EGLHelper.initDisplay()
        wrapper.createGLESWithSurface(surface = holder.surface!!)
        flatProgram = GlSimpleProgram()
        drawAnimator.start()
    }

    private fun onSurfaceDestroyed() {
        drawAnimator.cancel()
        flatProgram?.release()
        flatProgram = null

        wrapper.release()
    }

    private fun draw() {
        Log.w("SHAPES", "drawing.")
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

        // Draw the circle.
        flatProgram!!.setColor(Color.RED)
        circle.radius = floatValue(1F, 0F)
        scene.draw(flatProgram!!, circle)
        // Publish.
        wrapper.swapBuffers()
        Logger.e(MatrixState.printMatrix(circle.modelMatrix))
    }

    private fun intValue(start: Int, end: Int): Int {
        return floatValue(start.toFloat(), end.toFloat()).roundToInt()
    }

    private fun floatValue(start: Float, end: Float): Float {
        return start + drawAnimator.animatedFraction * (end - start)
    }

    override fun onDestroy() {
        onSurfaceDestroyed()
        super.onDestroy()
    }

    override fun gestureStateChanged(event: MotionEvent, recognizer: GestureRecognizer) {
        if (recognizer === panRecognizer) {
            Logger.e(
                "panRecognizer > \n" +
                        "panX = ${recognizer.panX()} \n " +
                        "panY = ${recognizer.panY()} \n "
            )
        } else if (recognizer === pinchRecognizer) {
            val scale = recognizer.scale()
            Logger.e(
                "pinchRecognizer > \n" +
                        "scale = ${scale} \n "
            )
        } else if (recognizer === rotationRecognizer) {
            val rotation = recognizer.rotation()
            Logger.e(
                "rotationRecognizer > \n" +
                        "rotation = ${rotation} \n "
            )
        }

        draw()

    }
}